
/**
 * Module Name: PassOne
 * Description: The Work from Pass 1.
 * Calling Sequence
 * 		Input Parameters 
 * 		Output Parameters 
 * Error Conditions Tested: 
 * Error Messages Generated: 
 * Original Author: Travis Casper
 * Procedure Creation Date: 10/22/09
 * Modification Log:
 * 	 Who/When/Why
 * 
 * Coding Standards Met: "Signed Code Leader(Jaron)"
 * Testing Standards Met: "Signed Test Leader(Jamie)"
 */

public class PassOne {
	protected static int lineNumber = 0;
	protected static int LC;
	private static String lineNumberString;

	public static String run() {
		Boolean endOccurred = new Boolean(Boolean.FALSE);
		Boolean debugIsOn = new Boolean(Boolean.FALSE);
		Boolean brFlagIsOn = new Boolean(Boolean.FALSE);
		Boolean wrongFirstLine = new Boolean(Boolean.FALSE);
		Boolean usingIsUsed = new Boolean(Boolean.FALSE);
		Boolean changeLineToNOP = new Boolean(Boolean.FALSE);

		String startSymbol = "";
		int skipValue = 0;
		int totalLength = SourceCode.returnOriginalCodeLength();

		LC = 0; // location counter
		lineNumber = 0; // line number

		Main.appendDebugText(Main.newline + "Finished Calculating Total LC");
		Main.appendDebugText(Main.newline + "Starting PassOne");
		while (lineNumber < totalLength) {
			lineNumberString = new String(Integer.toString(lineNumber));
			String codeLine = SourceCode.returnNextLine();
			Main.appendDebugText(Main.newline + "Line # =\t" + lineNumber);
			Main.appendDebugText("Current Line:\t" + codeLine);
			IntermediateFile.newLine(codeLine);
			ParseLine currentLine = new ParseLine(codeLine);
			if (!wrongFirstLine) {
				if (!endOccurred) {
					if (currentLine.isEmptyLine()) {
						Main.appendDebugText("EMPTY LINE");
						IntermediateFile.addEmptyLine();
						IntermediateFile.finishLine();
						lineNumber++;
					} else if (currentLine.label() == null && currentLine.instruction() == null && currentLine.operand() == null && currentLine.comment() != null) {
						Main.appendDebugText("WHOLE LINE IS COMMENT");
						IntermediateFile.finishLine();
						lineNumber++;
					} else if (LC > 4095) {
						Main.appendDebugText("PAST HARDWARE LIMIT 4095");
						IntermediateFile.finishLine();
						lineNumber = SourceCode.returnOriginalCodeLength();
					}
					else {
						if (lineNumber == 0) {

							Boolean containsStart = currentLine.instruction().toUpperCase().contains("START");
							Main.appendDebugText("First Line Start?\t\t" + !containsStart);
							if (!containsStart) {
								// ERROR: START FAILURE
								Main.appendDebugText("START FAILURE");
								ErrorHandler.addToErrorList(lineNumberString, "19");
								if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
									IntermediateFile.changeLineToNOP(lineNumber);
								}
								wrongFirstLine = Boolean.TRUE;
								lineNumber = SourceCode.returnOriginalCodeLength();
								IntermediateFile.finishLine();
							}
						}
						if (!wrongFirstLine) {
							// if the OPERATION is defined in the MOT table then it is
							// a Machine Instruction
							Main.appendDebugText("CURRENT OPERATION:\t" + currentLine.instruction());
							System.out.println("CURRENT OPERATION:\t" + currentLine.instruction());
							if (MOTtable.mnemonicIsDefined(currentLine.instruction())) {

								// check for Label Error
								if (currentLine.label() != null) {
									Main.appendDebugText("MOT CURRENT LABEL:\t" + currentLine.label());
									System.out.println("MOT CURRENT LABEL: " + currentLine.label());
									// check if label is in symbol table
									if (SymbolTable.symbolIsDefined(currentLine.label())) {
										System.out.println("ERROR: SYMBOL ALREADY DEFINED(MOT)");
										// ERROR: CANNOT DEFINE PREVIOUSLY DEFINED SYMBOL
										ErrorHandler.addToErrorList(lineNumberString, "8", currentLine.label() + " has been defined");
										if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
											IntermediateFile.changeLineToNOP(lineNumber);
										}
									} else {
										if (OperandType.isValidLabelType(currentLine.label())) {
											// Label is Not in Symbol Table
											// Add Symbol
											String symbol = currentLine.label();
											SymbolTable.addSymbol(symbol);
											// We know the line has a symbol, Add it to the Intermediate File
											IntermediateFile.addLabel(symbol);
											SymbolTable.editLocationAddress(symbol, Integer.toString(LC));
											SymbolTable.editLength(symbol, "1");
											if (brFlagIsOn) {
												SymbolTable.editRelocationCode(symbol, "B");
											} else {
												SymbolTable.editRelocationCode(symbol, "R");
											}
											SymbolTable.editUsage(symbol, "Instruction Label");
											SymbolTable.editEQUValue(symbol, "n/a");
										} else {
											// ERROR: INVALID LABEL
											ErrorHandler.addToErrorList(lineNumberString, "4");

										}
									}
								}

								//Literals must be done before LC increments
								// Machine Instructions always use Memory, increment LC
								// We know the current LC value, Add it to the Intermediate File
								IntermediateFile.addLocationCounter(LC);
								LC++;

								// We know the OPERATION is correct,
								// Add it to the Intermediate File
								IntermediateFile.addOperation(currentLine.instruction());
								// Add the Binary Value to the Intermediate File
								IntermediateFile.addBinaryOperation(MOTtable.returnBinaryForMnemonic(currentLine.instruction()));
								// Determine Register Flags
								if (MOTtable.usesAR(currentLine.instruction())) {
									IntermediateFile.turnOnAR();
								} else if (MOTtable.usesIR(currentLine.instruction())) {
									IntermediateFile.turnOnIR();
								}

								if (currentLine.operand() != null) {
									Main.appendDebugText("OPERAND IS:\t" + currentLine.operand());

									System.out.println("\t\tOPERAND IS " + currentLine.operand());
									System.out.println("\t\tOPERAND TYPE IS " + MOTtable.operandType(currentLine.instruction()));

									OperandType opType = new OperandType();
									if (!(opType.validateOperandType(currentLine.operand(), MOTtable.operandType(currentLine.instruction()), true))) {
										System.out.println("ERROR INVALID OPERAND TYPE");
										// ERROR: INVALID OPERAND TYPE
										Main.appendDebugText("INVALID OPERAND TYPE");
										//ErrorHandler.addToErrorList(lineNumberString, "6");
										if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
											IntermediateFile.changeLineToNOP(lineNumber);
										}
									} else {
										String[] operands = ParseLine.parseOperands(currentLine.operand());
										switch (MOTtable.operandType(currentLine.instruction())) {
										case TYPE3:
											IntermediateFile.addFullOperand(currentLine.operand());
											Main.appendDebugText("OPERAND TYPE: TYPE3");
											System.out.println("OPERAND TYPE: TYPE3");
											for (String op : operands) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
												}
											}
											break;
										case TYPE4:
											IntermediateFile.addFullOperand(currentLine.operand());
											Main.appendDebugText("OPERAND TYPE: TYPE4");
											System.out.println("OPERAND TYPE: TYPE4");
											for (String op : operands) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
												}
											}
											break;
										case REF1:
											IntermediateFile.addFullOperand(currentLine.operand());
											Main.appendDebugText("OPERAND TYPE: REF1");
											System.out.println("OPERAND TYPE: REF1");
											for (String op : operands) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
													if ((op.contains("="))) {
														addLiteralToSymbolTable(op);
													}
												}
											}
											break;
										case REFALL:
											IntermediateFile.addFullOperand(currentLine.operand());
											Main.appendDebugText("OPERAND TYPE: REFALL");
											System.out.println("OPERAND TYPE: REFALL");
											if (currentLine.operand().contains("#")) {
												Main.appendDebugText("\tOPERAND TYPE: REF2");
												System.out.println("\tOPERAND TYPE: REF2");
												for (String op : operands) {
													if (op != null) {
														System.out.println("OPERAND is: " + op);
														Main.appendDebugText("OPERAND is: " + op);
														op = op.replaceAll("#", "");
														IntermediateFile.addAnOperand(op);
														if ((op.contains("="))) {
															addLiteralToSymbolTable(op);
														}
													}
												}
												IntermediateFile.turnOnDirectAddressing();
												System.out.println("DIRECT ADDRESSING");
												Main.appendDebugText("DIRECT ADDRESSING");
											} else if (opType.validateOperandType(currentLine.operand(), OperandType.operandType.REF1, false)) {
												Main.appendDebugText("\tOPERAND TYPE: REF1");
												System.out.println("\tOPERAND TYPE: REF1");
												for (String op : operands) {
													if (op != null) {
														System.out.println("OPERAND is: " + op);
														Main.appendDebugText("OPERAND is: " + op);
														IntermediateFile.addAnOperand(op);
														if ((op.contains("="))) {
															addLiteralToSymbolTable(op);
														}
													}
												}
												IntermediateFile.turnOnRelativeAddressing();
												System.out.println("RELATIVE ADDRESSING");
												Main.appendDebugText("RELATIVE ADDRESSING");
											} else if (opType.validateOperandType(currentLine.operand(), OperandType.operandType.REF3, false)) {
												System.out.println("\tOPERAND TYPE: REF3");
												Main.appendDebugText("\tOPERAND TYPE: REF3");
												for (String op : operands) {
													if (op != null) {
														System.out.println("OPERAND is: " + op);
														Main.appendDebugText("OPERAND is: " + op);
														op = op.replaceAll("%", "");
														IntermediateFile.addAnOperand(op);
														if ((op.contains("="))) {
															addLiteralToSymbolTable(op);
														}
													}
												}
												IntermediateFile.turnOnIndirectAddressing();
												System.out.println("INDIRECT ADDRESSING");
												Main.appendDebugText("INDIRECT ADDRESSING");
											} else {
												System.out.println("OPERAND TYPE: REFEXP");
												Main.appendDebugText("OPERAND TYPE: REFEXP");
												String[] expOperands = ParseLine.parseExpression(currentLine.operand());
												for (String op : expOperands) {
													if (op != null) {
														System.out.println("OPERAND is: " + op);
														Main.appendDebugText("OPERAND is: " + op);
														IntermediateFile.addAnOperand(op);
														if ((op.contains("="))) {
															addLiteralToSymbolTable(op);
														}
													}
												}
											}
											break;
										case STAR:
											System.out.println("OPERAND TYPE: STAR");
											Main.appendDebugText("OPERAND TYPE: STAR");
											for (String op : operands) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													if (op.equals("*")) {
														Integer lcValue = new Integer(LC);
														IntermediateFile.addFullOperand(lcValue.toString());
														IntermediateFile.addAnOperand(lcValue.toString());
													}
													IntermediateFile.addAnOperand(op);
												}
											}
											break;
										}
									}
								} else {
									if (MOTtable.operandType(currentLine.instruction()) != OperandType.operandType.NONE) {
										// ERROR: INVALID OPERAND TYPE
										Main.appendDebugText("INVALID OPERAND TYPE");
										ErrorHandler.addToErrorList(lineNumberString, "6");
										if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
											IntermediateFile.changeLineToNOP(lineNumber);
										}
									}
								}
								//PSEUDO OPS
							} else if (POTtable.isDefined(currentLine.instruction())) {
								// else if the OPERATION is defined in the POT table then it is a
								// directive

								// if the directive consumes memory then increment LC
								if (POTtable.consumesMemory(currentLine.instruction())) {

									// We know the current LC value, Add it to the Intermediate File
									IntermediateFile.addLocationCounter(LC);
									LC++;
								} else {
									// We know the current LC value anyways, Add it to the Intermediate File
									IntermediateFile.addLocationCounter(LC);
								}
								// check if the directive can have a label
								if (POTtable.canHaveLabel(currentLine.instruction())) {
									if (currentLine.label() != null) {
										// check if the directive requires a label
										System.out.println(currentLine.label());
										// check to see if label is valid
										if (OperandType.isValidLabelType(currentLine.label())) {
											if (POTtable.requiresLabel(currentLine.instruction())) {
												if (currentLine.label() == null) {
													System.out.println("ERROR: LABEL is Required but not Present");
													// ERROR: REQUIRED LABEL NOT PRESENT
													Main.appendDebugText("REQUIRED LABEL NOT PRESENT");
													ErrorHandler.addToErrorList(lineNumberString, "13", currentLine.instruction() + " Requires a Label, but there is not a label present");
													if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
														IntermediateFile.changeLineToNOP(lineNumber);
													}
												} else {
													System.out.println("CURRENT LABEL: " + currentLine.label());
													// We know the OPERATION is correct
													// Add it to the Intermediate File
													IntermediateFile.addOperation(currentLine.instruction());
													// if Label is not already defined in Symbol Table

													if (SymbolTable.symbolIsDefined(currentLine.label())) {
														System.out.println("ERROR: SYMBOL ALREADY DEFINED (POT)");
														// ERROR: CANNOT DEFINE PREVIOUSLY DEFINED SYMBOL
														Main.appendDebugText("CANNOT DEFINE PREVIOUSLY DEFINED SYMBOL");
														ErrorHandler.addToErrorList(lineNumberString, "8", currentLine.label() + " has been defined");
														if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
															IntermediateFile.changeLineToNOP(lineNumber);
														}
													} else {
														// START
														System.out.println("OPERATION: " + currentLine.instruction().toUpperCase());
														Main.appendDebugText("OPERATION: " + currentLine.instruction().toUpperCase());
														if (currentLine.instruction().equalsIgnoreCase("START")) {
															startSymbol = currentLine.label();

															//startLabel = symbol;
															LC = Integer.valueOf(currentLine.operand());
															IntermediateFile.addLabel(startSymbol);
															SymbolTable.addSymbol(startSymbol);
															SymbolTable.editLocationAddress(startSymbol, Integer.toString(LC));
															SymbolTable.editRelocationCode(startSymbol, "R");
															SymbolTable.editUsage(startSymbol, "Program Name");
															SymbolTable.editEQUValue(startSymbol, "n/a");
														}

													}
												}
											} else {
												if (currentLine.label() == null) {
													Main.appendDebugText("CURRENT LABEL: " + currentLine.label());
													System.out.println("CURRENT LABEL: " + currentLine.label());
													IntermediateFile.addOperation(currentLine.instruction());
												} else if (SymbolTable.symbolIsDefined(currentLine.label())) {
													System.out.println("ERROR: SYMBOL ALREADY DEFINED");
													// ERROR: CANNOT DEFINE PREVIOUSLY DEFINED SYMBOL
													ErrorHandler.addToErrorList(lineNumberString, "8", currentLine.label() + " has been defined");
													if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
														IntermediateFile.changeLineToNOP(lineNumber);
													}
												} else {
													Main.appendDebugText("CURRENT LABEL: " + currentLine.label());
													System.out.println("CURRENT LABEL: " + currentLine.label());
													IntermediateFile.addOperation(currentLine.instruction());
													// Label is Not in Symbol Table
													// Add Symbol
													String symbol = currentLine.label();
													SymbolTable.addSymbol(symbol);
													// We know the line has a symbol, Add it to the Intermediate File
													IntermediateFile.addLabel(symbol);
													SymbolTable.editLocationAddress(symbol, Integer.toString(LC));
													SymbolTable.editLength(symbol, "1");
													if (brFlagIsOn) {
														SymbolTable.editRelocationCode(symbol, "B");
													} else {
														SymbolTable.editRelocationCode(symbol, "R");
													}
													SymbolTable.editUsage(symbol, "Instruction Label");
													SymbolTable.editEQUValue(symbol, "n/a");
												}
											}
										} else {
											// ERROR: INVALID LABEL
											ErrorHandler.addToErrorList(lineNumberString, "4");
										}
									} else {
										// Line can have label but does not
										IntermediateFile.addOperation(currentLine.instruction());
									}
								}

								// check if directive is NOT allowed to have a label
								if (!(POTtable.canHaveLabel(currentLine.instruction()))) {
									// if it is not allowed to have a label then the currentLine
									// label value should be null
									if (currentLine.label() != null) {
										// ERROR: NO LABEL ALLOWED
										Main.appendDebugText("NO LABEL ALLOWED");
										ErrorHandler.addToErrorList(lineNumberString, "14", "The current instruction " + currentLine.instruction() + " does not allow a label");
									}
									// We know the OPERATION is correct,
									// Add it to the Intermediate File
									IntermediateFile.addOperation(currentLine.instruction());
								}

								// if OPERATION is END
								if (currentLine.instruction().equalsIgnoreCase("END")) {
									endOccurred = Boolean.TRUE;
								}

								// if OPERATION is USING
								if (currentLine.instruction().equalsIgnoreCase("USING")) {
									if (LC != 0) {
										//ERROR: INVALID USING SYNTAX
										ErrorHandler.addToErrorList(lineNumberString, "29");
										Main.appendDebugText("INVALID USING SYNTAX");
										if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
											IntermediateFile.changeLineToNOP(lineNumber);
										}
									} else {
										usingIsUsed = Boolean.TRUE;
									}
								}

								if (currentLine.operand() != null) {
									// operand type in the operand field of the parsed line
									OperandType opType = new OperandType();
									Main.appendDebugText("CURRENT OPERAND: " + currentLine.operand());
									System.out.println("CURRENT OPERAND: " + currentLine.operand());
									System.out.println("CURRENT OPERAND TYPE: " + POTtable.operandType(currentLine.instruction()).toString());
									if (!(opType.validateOperandType(currentLine.operand(), POTtable.operandType(currentLine.instruction()), true))) {

										System.out.println("ERROR: INVALID OPERAND TYPE");
										// ERROR: INVALID OPERAND TYPE
										Main.appendDebugText("INVALID OPERAND TYPE");
										ErrorHandler.addToErrorList(lineNumberString, "6");
										if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
											IntermediateFile.changeLineToNOP(lineNumber);
										}
									} else {

										String fOperand = currentLine.operand();
										IntermediateFile.addFullOperand(fOperand);
										Main.appendDebugText("POT Operands");
										System.out.println("POT Operands");
										switch (POTtable.operandType(currentLine.instruction())) {

										case TYPE1:
											Main.appendDebugText("OPERAND TYPE: TYPE1");
											System.out.println("OPERAND TYPE: TYPE1");
											String[] operands = ParseLine.parseOperands(currentLine.operand());
											if (currentLine.instruction().equalsIgnoreCase("START")) {

											} else {
												for (String op : operands) {
													if (op != null) {
														System.out.println("OPERAND is: " + op);
														Main.appendDebugText("OPERAND is: " + op);
														if (op.equalsIgnoreCase("*")) {
															op = Integer.toString(LC);
														}
														IntermediateFile.addAnOperand(op);
														if (currentLine.instruction().equalsIgnoreCase("EQU")) {
															String symbol = currentLine.label();
															if (!ErrorHandler.lineHasErrorIntermediateError(lineNumber)) {
																if (SymbolTable.symbolIsDefined(symbol)) {
																	SymbolTable.editEQUValue(symbol, op);
																} else {
																	IntermediateFile.addLabel(symbol);
																	SymbolTable.addSymbol(symbol);
																	SymbolTable.editLocationAddress(symbol, "n/a");
																	SymbolTable.editLength(symbol, "n/a");
																	if (brFlagIsOn) {
																		SymbolTable.editRelocationCode(symbol, "B");
																	} else {
																		SymbolTable.editRelocationCode(symbol, "R");
																	}
																	SymbolTable.editUsage(symbol, "EQU VALUE");
																	SymbolTable.editEQUValue(symbol, op);
																}
															}
														}
													}
												}
											}
											IntermediateFile.addRelocationCode("R");
											break;
										case TYPE2:
											// Only two Operations with TYPE2 Operands, RESET-LC & SKIP-mem
											System.out.println("OPERAND TYPE: TYPE2");
											String[] operands1 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands1) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													if (currentLine.instruction().equalsIgnoreCase("SKIP-MEM")) {
														int opValue = 0;
														try {
															opValue = Integer.parseInt(op);
															//LC += opValue;
														} catch (NumberFormatException e) {
															ErrorHandler.addToErrorList(lineNumberString, "3", "The Operand " + op + " is not a Number");
														}
														skipValue = opValue;
													} else if (currentLine.instruction().equalsIgnoreCase("RESET-LC")) {
														try {
															int opValue = Integer.parseInt(op);
															if (opValue <= LC) {
																ErrorHandler.addToErrorList(lineNumberString, "3", "The Operand " + op + " is not greater than the last assigned LC");
															} else {
																LC = opValue;
															}
														} catch (NumberFormatException e) {
															ErrorHandler.addToErrorList(lineNumberString, "3", "The Operand " + op + " is not a Number");
														}
													}
												}
											}
											IntermediateFile.addRelocationCode("R");
											break;
										case EXPRESSION1:
											// TODO CHECK EXPRESSION 1 for RANGE?
											// TODO CHECK EXPRESSION 1 for SYMBOL
											System.out.println("OPERAND TYPE: EXPRESSION1");
											String[] operands4 = ParseLine.parseExpression(currentLine.operand());
											for (String op : operands4) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
													if ((op.contains("="))) {
														addLiteralToSymbolTable(op);
													}
												}
											}
											String symbol = currentLine.label();
											if (!ErrorHandler.lineHasErrorIntermediateError(lineNumber)) {
												Integer opValue = OperandEvaluator.evaluateOperand(lineNumber);
												String opValueString = opValue.toString();
												if (SymbolTable.symbolIsDefined(symbol)) {
													SymbolTable.editEQUValue(symbol, opValueString);
												} else {
													IntermediateFile.addLabel(symbol);
													SymbolTable.addSymbol(symbol);
													SymbolTable.editLocationAddress(symbol, "n/a");
													SymbolTable.editLength(symbol, "n/a");
													if (brFlagIsOn) {
														SymbolTable.editRelocationCode(symbol, "B");
													} else {
														SymbolTable.editRelocationCode(symbol, "R");
													}
													SymbolTable.editUsage(symbol, "EQU VALUE");
													SymbolTable.editEQUValue(symbol, opValueString);
												}
											}
											break;
										case EXPRESSION2:
											// TODO CHECK EXPRESSION 2 for RANGE?
											// TODO CHECK EXPRESSION 2 for SYMBOL
											System.out.println("OPERAND TYPE: EXPRESSION2");
											String[] operands5 = ParseLine.parseExpression(currentLine.operand());
											System.out.println("Size of Expression2 Operands " + Integer.toString(operands5.length));
											for (String op : operands5) {
												System.out.println("OPERAND: " + op);
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
													if ((op.contains("="))) {
														addLiteralToSymbolTable(op);
													}
												}
											}
											LC+=2;
											break;
										case EXPRESSION3:
											// TODO CHECK EXPRESSION 1 for SYMBOL
											System.out.println("OPERAND TYPE: EXPRESSION3");
											String[] operands6 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands6) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
												}
											}
											break;
										case REF1:
											System.out.println("OPERAND TYPE: REF1");
											String[] operands7 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands7) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
													if ((op.contains("="))) {
														addLiteralToSymbolTable(op);
													}
												}
											}
											break;
										case ONOFF:
											System.out.println("OPERAND TYPE: ONOFF");
											String[] operands8 = ParseLine.parseOperands(currentLine.operand());

											if (operands8[0] != null) {
												String op = operands8[0];
												System.out.println("OPERAND is: " + op);
												Main.appendDebugText("OPERAND is: " + op);
												// op is either ON or OFF
												op = op.toUpperCase();
												// If Debug is ON, and OPERAND is OFF, Turn it OFF
												if (debugIsOn && op.contains("OFF")) {
													IntermediateFile.turnOffDebug();
													IntermediateFile.addAnOperand(op);
													debugIsOn = Boolean.FALSE;
												} else if (!debugIsOn && op.contains("ON")) {
													// If Debug is OFF, and OPERAND is ON, Turn it ON
													IntermediateFile.turnOnDebug();
													IntermediateFile.addAnOperand(op);
													debugIsOn = Boolean.TRUE;
												} else if (debugIsOn && op.contains("ON")) {
													// ERROR: DEBUG IS ALREADY ON
													System.out.println("ERROR: DEBUG is already ON");
													Main.appendDebugText("ERROR: DEBUG is already ON");
													ErrorHandler.addToErrorList(lineNumberString, "15");
												} else if (!debugIsOn && op.contains("OFF")) {
													// ERROR: DEBUG IS ALREADY OFF
													System.out.println("ERROR: DEBUG is already OFF");
													Main.appendDebugText("ERROR: DEBUG is already OFF");
													ErrorHandler.addToErrorList(lineNumberString, "16");
												}
											}

											for (int i1 = 1; i1 < operands8.length; i1++) {
												if (operands8[i1] != null) {
													System.out.println("ERROR: TOO MANY OPERANDS AFTER DEBUG");
													// ERROR: DEBUG DIRECTIVE HAS TOO MANY OPERANDS
													ErrorHandler.addToErrorList(lineNumberString, "24", currentLine.operand() + " is an operand with more than ON or OFF");
												}
											}
											break;
										case NONE:
											System.out.println("OPERAND TYPE: NONE");
											// Could be USING or NOP
											if (currentLine.instruction().equalsIgnoreCase("USING")) {
												System.out.println("USING");
												if (brFlagIsOn) {
													System.out.println("\t\tERROR: USING HAS ALREADY BEEN USED");
													// ERROR: USING HAS BEEN USED
													Main.appendDebugText("ERROR: USING HAS ALREADY BEEN USED");
													ErrorHandler.addToErrorList(Integer.toString(lineNumber), "27", "USING HAS ALREADY BEEN USED");
													if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
														IntermediateFile.changeLineToNOP(lineNumber);
													}
												} else {
													brFlagIsOn = Boolean.TRUE;
												}
											} else if (!currentLine.instruction().equalsIgnoreCase("USING")){
												IntermediateFile.addNOP();
											}
											break;
										case LABEL:
											System.out.println("OPERAND TYPE: LABEL");
											String[] operands9 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands9) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
													if (SymbolTable.symbolIsDefined(op)) {
														// ERROR: CANNOT DEFINE PREVIOUSLY DEFINED SYMBOL
														ErrorHandler.addToErrorList(lineNumberString, "8", op + " has already been defined in the Symbol Table");
														if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
															IntermediateFile.changeLineToNOP(lineNumber);
														}
													}
												}
											}
											break;
										case EXLABEL:
											System.out.println("OPERAND TYPE: EXLABEL");
											String[] operands10 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands10) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
													// EXTERNAL
													if (SymbolTable.symbolIsDefined(op)) {
														// ERROR: CANNOT DEFINE PREVIOUSLY DEFINED SYMBOL
														ErrorHandler.addToErrorList(lineNumberString, "8", op + " has already been defined in the Symbol Table");
														if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
															IntermediateFile.changeLineToNOP(lineNumber);
														}
													}
													symbol = op;
													IntermediateFile.addLabel(symbol);
													SymbolTable.addSymbol(symbol);
													SymbolTable.editLocationAddress(symbol, "n/a");
													SymbolTable.editLength(symbol, "n/a");
													SymbolTable.editRelocationCode(symbol, "C");
													SymbolTable.editUsage(symbol, "EXTERNAL LABEL");
												}
											}
											IntermediateFile.addRelocationCode("C");
											break;
										case NUM:
											System.out.println("OPERAND TYPE: NUM");
											String[] operands11 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands11) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													String opValue = new String("");
													opValue = op.replace("+", "");
													opValue = op.replace("-", "");
													int value = Integer.parseInt(opValue);
													if (op.contains("-")) {
														value = 0 - value;
													}
													IntermediateFile.addAnOperand(op);
												}
											}
											IntermediateFile.addRelocationCode("A");
											break;
										case CHR:
											System.out.println("OPERAND TYPE: CHR");
											String[] operands12 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands12) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
												}
											}
											IntermediateFile.addRelocationCode("A");
											break;
										case HEX:
											System.out.println("OPERAND TYPE: HEX");
											String[] operands13 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands13) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op.toUpperCase());
												}
											}
											IntermediateFile.addRelocationCode("A");
											break;
										case BIN:
											System.out.println("OPERAND TYPE: BIN");
											String[] operands14 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands14) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
												}
											}
											IntermediateFile.addRelocationCode("A");
											break;
										case ADDR:
											System.out.println("OPERAND TYPE: ADDR");
											String[] operands15 = ParseLine.parseOperands(currentLine.operand());
											for (String op : operands15) {
												if (op != null) {
													System.out.println("OPERAND is: " + op);
													Main.appendDebugText("OPERAND is: " + op);
													IntermediateFile.addAnOperand(op);
												}
											}
											break;
										}
									}
								} else {
									if (POTtable.operandType(currentLine.instruction()) != OperandType.operandType.NONE) {
										// ERROR: INVALID OPERAND TYPE
										Main.appendDebugText("INVALID OPERAND TYPE");
										ErrorHandler.addToErrorList(lineNumberString, "6");
										if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
											IntermediateFile.changeLineToNOP(lineNumber);
										}
									}
								}
							} else {
								System.out.println("\tUNKNOWN OPERATION\t");
								// instruction was not found in either the MOT or the POT
								// ERROR: UNDEFINED INSTRUCTION
								ErrorHandler.addToErrorList(Integer.toString(lineNumber), "2", (currentLine.instruction() + " is an Unknown Operation"));
								Main.appendDebugText("UNDEFINED INSTRUCTION");
							}

							// check if a comment is present
							if (currentLine.comment() != null) {
								String comment = currentLine.comment();
								if (comment.charAt(0) != ':') {
									// ERROR: INVALID COMMENT
									ErrorHandler.addToErrorList(lineNumberString, "25", currentLine.comment() + " is an invalid comment");
									if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
										IntermediateFile.changeLineToNOP(lineNumber);
									}
								}
							}

							//TURN on BR flag for all code if using was used
							if (brFlagIsOn) {
								IntermediateFile.turnOnBR();
								if (IntermediateFile.returnRelocationCode(lineNumber) == "R") {
									IntermediateFile.editRelocationCode(lineNumber, "B");
								}
							}

							if (changeLineToNOP) {
								if (!usingIsUsed) {
									//ERROR: USE OF BR INSTRUCTION WITHOUT USING DIRECTIVE
									Main.appendDebugText("USE OF BR INSTRUCTION WITHOUT USING DIRECTIVE");
									ErrorHandler.addToErrorList(lineNumberString, "27", "A BR INSTRUCTION WAS USED BEFORE USING DIRECTIVE");
									if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
										IntermediateFile.changeLineToNOP(lineNumber);
									}
								}
								if (currentLine.instruction().equalsIgnoreCase("LD-BR")) {
									if (currentLine.operand() != null) {
										if (!currentLine.operand().equalsIgnoreCase("*")) {
											Main.appendDebugText("INVALID OPERAND FOR LD-BR");
											ErrorHandler.addToErrorList(lineNumberString, "6", "LD-BR REQUIRES * OPERAND, NOT " + currentLine.operand());
										}
									} else {
										Main.appendDebugText("INVALID OPERAND FOR LD-BR");
										ErrorHandler.addToErrorList(lineNumberString, "6", "LD-BR REQUIRES * OPERAND, NOT " + currentLine.operand());
										if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
											IntermediateFile.changeLineToNOP(lineNumber);
										}
									}
								}
							}
							IntermediateFile.finishLine();
							lineNumber++;
							while (skipValue != 0) {
								IntermediateFile.newLine(lineNumber, "NOP");
								IntermediateFile.addNOP(LC);
								IntermediateFile.finishLine(lineNumber);
								lineNumber++;
								LC++;
								if (lineNumber < totalLength) {
									totalLength++;
								}
								if (LC > 4095) {
									lineNumberString = String.valueOf(lineNumber);
									ErrorHandler.addToErrorList(lineNumberString, "18");
								}
								skipValue--;
							}
						}
					}

				} else {
					// ERROR: SOURCE CODE AFTER END, Extra lines of code added after END
					Main.appendDebugText("SOURCE CODE AFTER END");
					ErrorHandler.addToErrorList(lineNumberString, "23");
					if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
						IntermediateFile.changeLineToNOP(lineNumber);
					}
					IntermediateFile.finishLine();
					lineNumber = totalLength;
				}
			} else {
				// ERROR: START FAILURE
				Main.appendDebugText("START FAILURE");
				ErrorHandler.addToErrorList(lineNumberString, "19");
				if (POTtable.consumesMemory(currentLine.instruction()) || MOTtable.mnemonicIsDefined(currentLine.instruction())) {
					IntermediateFile.changeLineToNOP(lineNumber);
				}
				IntermediateFile.finishLine();
				lineNumber = SourceCode.returnOriginalCodeLength();
			}
		}
		finishLiterals();
		IntermediateFile.totalLC = LC;
		SymbolTable.editLength(startSymbol, Integer.toHexString(LC));
		String symbolTableOutput = SymbolTable.outputSymbolTable();
		String intermediateFileOutput = IntermediateFile.output(symbolTableOutput);
		Main.appendDebugText("PASS 1 COMPLETED!");
		System.out.println("PASS 1 COMPLETED!");
		return intermediateFileOutput;
	}

	/**
	 * @modulename 
	 * 
	 * @description 
	 * 
	 * @callsequence  
	 * 
	 * @inparam 
	 * 
	 * @outparam 
	 * 
	 * @errorstested 
	 * 
	 * @errorsgenerated 
	 * 
	 * @author
	 * 
	 * @createdate
	 * 
	 * @modlog Who/When/Why
	 * 
	 * Coding Standards Met: "Signed Code Leader(Jaron)"
	 * 
	 * Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	private static void finishLiterals() {
		String[] litArray = IntermediateFile.returnLiterals();
		for (String literal : litArray) {
			System.out.println("Literal is " + literal);
			String value = SymbolTable.returnEQUValue(literal);
			System.out.println("Literal value is " + value);
			try {
				Integer.parseInt(value);
				IntermediateFile.newLine(lineNumber, literal + "\tWORD-NUM\t" + value);
				IntermediateFile.addAnOperand(lineNumber, value);
				IntermediateFile.addOperation(lineNumber, "WORD-NUM");
				IntermediateFile.addFullOperand(lineNumber, value);
				IntermediateFile.addLabel(lineNumber, literal);
				IntermediateFile.addLocationCounter(lineNumber, LC);
				IntermediateFile.finishLine();
			} catch (NumberFormatException e) {
				IntermediateFile.newLine(lineNumber, literal + "\tWORD-CHR\t" + value);
				IntermediateFile.addAnOperand(lineNumber, value);
				IntermediateFile.addOperation(lineNumber, "WORD-CHR");
				IntermediateFile.addFullOperand(lineNumber, value);
				IntermediateFile.addLabel(lineNumber, literal);
				IntermediateFile.addLocationCounter(lineNumber, LC);
				IntermediateFile.finishLine();
			}
			LC++;
			lineNumber++;
		}
	}
	/**
	 * @modulename 
	 * 
	 * @description 
	 * 
	 * @callsequence  
	 * 
	 * @inparam 
	 * 
	 * @outparam 
	 * 
	 * @errorstested 
	 * 
	 * @errorsgenerated 
	 * 
	 * @author
	 * 
	 * @createdate
	 * 
	 * @modlog Who/When/Why
	 * 
	 * Coding Standards Met: "Signed Code Leader(Jaron)"
	 * 
	 * Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	private static boolean addLiteralToSymbolTable(String op) {
		String litOperand = op;
		String litValue = op;
		litValue = litValue.replaceAll("=", "");
		// If Symbol is already defined, move on.
		if (!SymbolTable.symbolIsDefined(op)) {
			try {
				SymbolTable.addSymbol(litOperand);
				SymbolTable.editUsage(litOperand, "LITERAL");
				SymbolTable.editLength(litOperand, "1");
				SymbolTable.editRelocationCode(litOperand, "R");
				SymbolTable.editEQUValue(litOperand, litValue);
				SymbolTable.editLocationAddress(litOperand, Integer.toString(LC));
				IntermediateFile.addLiteral(litOperand);
			} catch (NumberFormatException nfe) {

				String litChar = litValue.replace("'", "");
				System.out.println("LitChar is " + litChar);
				if (litChar.length() > 3) {
					//ERROR: INVALID LITERAL
					Main.appendDebugText("INVALID CHARACTER LITERAL");
					ErrorHandler.addToErrorList(lineNumberString, "26", op + " is too large to be a valid literal");
				} else {
					SymbolTable.editUsage(litOperand, "LITERAL");
					SymbolTable.editLength(litOperand, "1");
					SymbolTable.editRelocationCode(litOperand, "R");
					SymbolTable.editEQUValue(litOperand, litChar);
					SymbolTable.editLocationAddress(litOperand, Integer.toString(LC));
					IntermediateFile.addLiteral(litOperand);
				}
			}
		}
		return true;
	}
}
